<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      function Person() {}
      //   原型对象上的属性
      Person.prototype.foo = "foo";

      let per1 = new Person();
      //   实例对象的属性
      per1.prop = "some value";

      // 每一个函数类型的数据，都有一个叫做prototype的属性，这个属性指向的是一个对象，就是所谓的原型对象。
      console.log(Person); //function Person()

      console.log(per1); //Object { prop: "some value" }
      console.log(per1.prop); //some value
      console.log(per1.foo); //foo
      // 对于原型对象来说，它有个constructor属性，指向它的构造函数
      console.log(per1.__proto__.constructor); //function Person()

      // 原型链通俗易懂的理解就是可以把它想象成一个链条,互相连接构成一整串链子! 而原型链就是实例对象和原型对象之间的链接
      //   整个查找过程都是顺着__proto__属性，一步一步往上查找，形成了像链条一样的结构，这个结构，就是原型链
      console.log(per1.__proto__); //Object { foo: "foo", … }
      console.log(Person.prototype); //Object { foo: "foo", … }
      // 显示原型就是利用prototype属性查找原型，只是这个是函数类型数据的属性
      // 隐式原型是利用__proto__属性查找原型，这个属性指向当前对象的构造函数的原型对象，这个属性是对象类型数据的属性
      console.log(per1.__proto__ === Person.prototype); //true

      console.log(per1.__proto__.__proto__); //{}  // 相当于 Object构造函数 的原型对象
      console.log(Object.prototype); //{}
      console.log(per1.__proto__.__proto__ === Object.prototype); //true

      console.log(per1.__proto__.__proto__.__proto__); //null  // 相当于 Object 的原型对象的原型对象
    </script>
  </body>
</html>
